import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
  Index,
  ManyToMany,
  JoinTable,
  OneToMany,
  DeleteDateColumn,
} from 'typeorm';
import {
  IsOptional,
  IsString,
  MaxLength,
  IsNotEmpty,
  IsEnum,
  IsNumber,
  IsBoolean,
  IsISO8601,
} from 'class-validator';
import { Type } from 'class-transformer';
import { CrudValidationGroups } from '@nestjsx/crud';
import { Gender } from '@/enum';
import { User } from '@/modules/users/entities/user.entity';
import { Album } from './album.entity';
import { Song } from './song.entity';
import { ArtistEdition } from './artist-edition.entity';

const { CREATE, UPDATE } = CrudValidationGroups;

@Entity({ name: 'artists' })
export class Artist {
  @IsOptional({ always: true })
  @PrimaryGeneratedColumn()
  id: number;

  @Type(_type => Song)
  @ManyToMany(
    _type => Song,
    song => song.belongsToArtists,
  )
  @JoinTable()
  hasSongs: Song[];

  @Type(_type => Album)
  @ManyToMany(
    _type => Album,
    album => album.belongsToArtists,
  )
  @JoinTable()
  hasAlbums: Album[];

  @Type(_type => Album)
  @ManyToMany(
    _type => Album,
    album => album.hasProducers,
  )
  @JoinTable()
  hasProducedAlbums: Album[];

  @Type(_type => ArtistEdition)
  @OneToMany(
    _type => ArtistEdition,
    edition => edition.artist,
  )
  editions: ArtistEdition[];

  @Type(_type => User)
  @ManyToMany(
    _type => User,
    follower => follower.followedArtists,
  )
  followers: User[];

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsNumber({}, { always: true })
  @Column({ type: 'int', default: 0 })
  followersCount = 0;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsString({ always: true })
  @MaxLength(80, { always: true })
  @Index({ unique: true })
  @Column({ type: 'character varying', length: 80 })
  name: string;

  @IsOptional({ always: true })
  @IsString({ each: true, always: true })
  @MaxLength(80, { each: true, always: true })
  @Index()
  @Column({
    type: 'character varying',
    length: 80,
    array: true,
    default: () => 'array[]::character varying[]',
  })
  alternateNames: string[];

  @IsOptional({ always: true })
  @IsEnum(Gender, { always: true })
  @Column({ type: 'enum', enum: Gender, nullable: true })
  gender: Gender | null;

  @IsOptional({ always: true })
  @IsISO8601({}, { always: true })
  @Column({ type: 'date', nullable: true })
  birthday: Date;

  @IsOptional({ always: true })
  @IsString({ always: true })
  @Column({ type: 'text', nullable: true })
  description: string;

  @IsOptional({ always: true })
  @IsString({ each: true, always: true })
  @MaxLength(100, { always: true, each: true })
  @Column({
    type: 'character varying',
    length: 100,
    array: true,
    default: () => 'array[]::character varying[]',
  })
  images: string[];

  @IsOptional({ always: true })
  @IsBoolean({ always: true })
  @Column({ type: 'boolean', default: true })
  visible = true;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @DeleteDateColumn()
  deletedAt: Date;
}
